package orma

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

const (
	QueryDelimiter = "//"
)

var (
	Records = new(BeanRecords)
)

type (
	QueryBean struct {
		Limit       string `json:"limit" form:"limit"`
		Order       string `json:"order" form:"order"`
		OrderType   string `json:"order_type" form:"order_type"`
		Where       string `json:"where" form:"where"`
		TimeBetween string `json:"time_between" form:"time_between"`
		TimeColumn  string `json:"time_column" form:"time_column"`
	}
	BeanRecords struct {
		bean    interface{}
		Count   int64       `json:"count"`
		Records interface{} `json:"records"`
		Qb      *QueryBean  `json:"-"`
	}
)

func NewBeanRecords(bean interface{}, qb *QueryBean) *BeanRecords {
	sv := reflect.ValueOf(bean)
	if sv.Kind() != reflect.Ptr {
		panic("need a pointer for NewBeanRecords")
	}
	slice := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(bean)), 0, 0)
	beans := reflect.New(slice.Type())
	beans.Elem().Set(slice)
	return &BeanRecords{
		bean:    bean,
		Records: beans.Interface(),
		Qb:      qb,
	}
}

func (op *BeanRecords) List(qus ...string) (err error) {
	var (
		paramString, tum string

		limit      = make([]int, 0)
		paramSlice = make([]string, 0)
		maxRows    = 100
	)

	//取值范围处理
	for _, value := range strings.Split(op.Qb.Limit, ",") {
		a, _ := strconv.Atoi(value)
		limit = append(limit, a)
	}
	switch len(limit) {
	case 0:
		limit = []int{0, 10}
	case 1:
		limit = []int{0, limit[0]}
	case 2:
	}
	if limit[1] > maxRows {
		limit[1] = maxRows
	}

	if op.Qb.Order == "" {
		op.Qb.Order = "id"
	}

	if op.Qb.Where != "" {
		ps := strings.Split(op.Qb.Where, QueryDelimiter)
		paramSlice = append(paramSlice, ps...)
	}

	if op.Qb.TimeColumn == "" {
		tum = "updated"
	} else {
		tum = op.Qb.TimeColumn
	}

	if op.Qb.TimeBetween != "" {
		ts := strings.Split(op.Qb.TimeBetween, ",")
		if len(ts) == 2 {
			paramSlice = append(paramSlice, fmt.Sprintf("%s between '%s' AND '%s'", tum, ts[0], ts[1]))
		}
	}

	if len(qus) > 0 {
		paramSlice = append(paramSlice, qus...)
	}

	if len(paramSlice) > 0 {
		paramString = strings.Join(paramSlice, " AND ")
	}

	newSN := GetEngine().Where(paramString).Limit(limit[1], limit[0])
	if strings.ToUpper(op.Qb.OrderType) == "ASC" {
		newSN = newSN.Asc(op.Qb.Order)
	} else {
		newSN = newSN.Desc(op.Qb.Order)
	}

	//检查是否是拥有密码的表,不获取密码
	if tableBean, ok := op.bean.(TableWithPassword); ok {
		newSN = newSN.Omit(tableBean.PasswordFieldName())
	}

	if err = newSN.Find(op.Records); err != nil {
		return
	}
	op.Count, err = GetEngine().Where(paramString).Count(op.bean)
	return
}
